﻿#light

module AstDomAdapter

open Might.Infrastructure.ModelicaDOM
open Might.Infrastructure.ModelicaDOM.Modifications
open Might.Infrastructure.ModelicaDOM.Expressions
open Might.Infrastructure.ModelicaDOM.Equations
open Might.Infrastructure.DOM
open Might.Modelica
open System
open System.Collections.ObjectModel
open AstTypes
open Microsoft.Practices.Unity
open Might.Infrastructure.Services
open DomTypesImpl


let mutable container:IUnityContainer = null

let log(message:string) = 
    let loggingService = container.Resolve(typeof<IMightLogger>) :?> IMightLogger
    loggingService.Log(new System.Object(),message)
    
let getDomRoot() =
    container.Resolve(typeof<IDom>) :?> IDom    

(*
//**************** TEST
let mutable testDomRoot:IDom = null

let mutable logMessages = String.Empty

let log(message:string) = 
    logMessages <- logMessages + message + System.Environment.NewLine
    
    
let getDomRoot() =
    testDomRoot

//******************* TEST
*)
let rec getClassQualifiedName(domNode:IDomNode) =
    match domNode with
    | :? IDom ->
        ""
    | _ ->
        let name = getClassQualifiedName(domNode.Parent) + "." + (domNode :?> IModelicaClass).ClassName
        String.trim ['.'] name

let prepareDomRoot(domRoot:IDomNode) =     
    let mutable mdlBuiltInType = new ModelicaClass()
    (mdlBuiltInType :> IModelicaClass).ClassName <- "Integer"
    (mdlBuiltInType:> IModelicaClass).RestrictedType <- ModelicaClassType.Predefined
    mdlBuiltInType.Parent <- domRoot
    domRoot.InsertChild(GroupNames.ModelicaClasses,mdlBuiltInType)
    
    mdlBuiltInType <- new ModelicaClass()
    (mdlBuiltInType :> IModelicaClass).ClassName <- "Real"
    (mdlBuiltInType :> IModelicaClass).RestrictedType <- ModelicaClassType.Predefined
    mdlBuiltInType.Parent <- domRoot
    domRoot.InsertChild(GroupNames.ModelicaClasses,mdlBuiltInType)
    
    mdlBuiltInType <- new ModelicaClass() 
    (mdlBuiltInType :> IModelicaClass).ClassName <- "String"
    (mdlBuiltInType :> IModelicaClass).RestrictedType <- ModelicaClassType.Predefined
    mdlBuiltInType.Parent <- domRoot
    domRoot.InsertChild(GroupNames.ModelicaClasses,mdlBuiltInType)
    
    mdlBuiltInType <- new ModelicaClass()
    (mdlBuiltInType :> IModelicaClass).ClassName <- "Boolean"
    (mdlBuiltInType :> IModelicaClass).RestrictedType <- ModelicaClassType.Predefined
    mdlBuiltInType.Parent <- domRoot
    domRoot.InsertChild(GroupNames.ModelicaClasses,mdlBuiltInType)
     
let insertMappedAnnotationToDomNode(annot:Annotation, domNode:DomNode,annotGroup:string) = 
    let annotNodeItem = new DomNode()
    try
        AnnotationMapper.MapAnnotation(annot._annotationBody,annotNodeItem)
    with
      | e ->        
        let errorLocation = 
            match domNode with
            | :? ModelicaClass ->
                "class " + getClassQualifiedName(domNode :> IDomNode)
            | :? ModelicaComponent ->
                "class " + getClassQualifiedName(domNode.Parent) + " and component " + ((domNode :?> ModelicaComponent) :> IComponent).ComponentName
            | :? ConnectClause ->
                "class " + getClassQualifiedName(domNode.Parent) + " and connect clause"
            | :? InheritanceDeclaration ->
                "class " + getClassQualifiedName(domNode.Parent) + " and extends clause " + (domNode :?> InheritanceDeclaration).baseClassName
            | _ ->
                "unknown spot type " + domNode.ToString()        
        log("Annotation mapping error in " + errorLocation + ": " + e.Message)
          
    domNode.InsertChild(annotGroup,annotNodeItem)
        
let findInsertionPointForAstSubtree(cls:Class) = ()     

// Creates Dom component from Ast, including annotation mapping and modifications        
let rec createDomComponentFromAst(astComp:AstTypes.Component) = 
    let domComp = new ModelicaComponent()
    domComp.refStatus <- ReferenceStatus.Unresolved
    domComp.typeName <- astComp._type._name
    (domComp :> IComponent).ComponentName <- astComp._name
    (domComp :> IComponent).ComponentVisibility <- astComp._visibility    
    match astComp._comment._annotation with
    | Some annot ->
        insertMappedAnnotationToDomNode(annot,domComp,GroupNames.Annotations)
    | _ -> ()
    match astComp._modification with
    | Some modif ->
        createDomSubtreeFromClassModification(modif,(domComp :> IDomNode))                
    | None -> ()
    domComp

and resolveElseIfEquations(elseifList : (Expression * (Equation list)) list,domNode:IDomNode) =
    for (expr,eqList) in elseifList do
        let elseIfEq = new ElseIfEquation()
        (elseIfEq :> IElseIfEquation).Condition <- expr
        resolveEquations(eqList,elseIfEq,GroupNames.ModelicaEquations)
        domNode.InsertChild(GroupNames.ModelicaElseWhenEquations,elseIfEq)
 
and resolveElseWhenEquations(elseifList : (Expression * (Equation list)) list,domNode:IDomNode) = 
    for (expr,eqList) in elseifList do
        let elseWhenEq = new ElseWhenEquation()
        (elseWhenEq :> IElseWhenEquation).Condition <- expr
        resolveEquations(eqList,elseWhenEq,GroupNames.ModelicaEquations)
        domNode.InsertChild(GroupNames.ModelicaElseWhenEquations,elseWhenEq)

and resolveEquations(eqList:Equation list,domNode:IDomNode,eqGroup:string) = 
    for eq in eqList do 
        match eq with
        | Equation.ConnClause (connClause,comment) ->
            let domConnClause = new ConnectClause()
            domConnClause.leftRefStatus <- ReferenceStatus.Unresolved
            domConnClause.rightRefStatus <- ReferenceStatus.Unresolved
            (domConnClause :> IConnectClause).LeftCompReference <- connClause._leftCompReference
            (domConnClause :> IConnectClause).RightCompReference <- connClause._rightCompReference
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domConnClause,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domConnClause)
        | Equation.EqFncCall (fncCall,comment) ->
            let domFncCall = new FncCallEquation()
            (domFncCall :> IFncCallEquation).FncName <- fncCall._funcName
            match fncCall._funcArgs with
            | Some fncArgs ->
                (domFncCall :> IFncCallEquation).FncArgs <- fncArgs
            | None -> ()
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domFncCall,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domFncCall)
        | Equation.ForEq(forEq,comment) ->
            let domForEq = new ForEquation()
            (domForEq :> IForEquation).Indices <- forEq._forIndices
            resolveEquations(forEq._equationList,domForEq,GroupNames.ModelicaEquations)
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domForEq,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domForEq)
        | Equation.SimpleEq (simpleEq,comment) ->
            let domSimpleEq = new SimpleEquation()
            (domSimpleEq :> ISimpleEquation).LeftExpression <- simpleEq._simpleExpLeft
            (domSimpleEq :> ISimpleEquation).RightExpression <- simpleEq._expRight
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domSimpleEq,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domSimpleEq)
        | Equation.IfEq (ifEq,comment) ->
            let domIfEq = new IfEquation()
            (domIfEq :> IIfEquation).Condition <- ifEq._condition
            resolveEquations(ifEq._thenEq,domIfEq,GroupNames.ModelicaThenEquations)
            resolveEquations(ifEq._elseEq,domIfEq,GroupNames.ModelicaElseEquations)            
            resolveElseIfEquations(ifEq._elseifList,domIfEq)
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domIfEq,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domIfEq)                  
        | Equation.WhenEq (whenEq,comment) ->
            let domWhenEq = new WhenEquation()
            (domWhenEq :> IWhenEquation).Condition <- whenEq._condition
            resolveEquations(whenEq._thenEq,domWhenEq,GroupNames.ModelicaThenEquations)            
            resolveElseWhenEquations(whenEq._elseWhenList,domWhenEq)
            match comment._annotation with
            | Some annot ->
                insertMappedAnnotationToDomNode(annot,domWhenEq,GroupNames.Annotations)
            | None -> ()
            domNode.InsertChild(GroupNames.ModelicaEquations,domWhenEq)

and resolveClassEquations(cls:Class,domCls:IModelicaClass) = 
    resolveEquations(cls._equations,(domCls:?> IDomNode),GroupNames.ModelicaEquations)
    resolveEquations(cls._initialEquations,(domCls:?> IDomNode),GroupNames.ModelicaInitialEquations)
            
and createDomClassFromAst(astClassList:AstTypes.Class list,parentDomNode:IDomNode,groupName) = 
    // for now just insert all classes as children of the root, later insertion point has to be found
    for cls in astClassList do
        //let insertionPoint = indInsertionPointForAstSubtree(cls)
        let  insertionPoint = parentDomNode        
        let mdlClass = new ModelicaClass() 
        (mdlClass :> IModelicaClass).ClassName <- cls._name
        (mdlClass :> IModelicaClass).RestrictedType <- cls._restrictedType
        (mdlClass :> IModelicaClass).Encapsulated <- cls._encapsulated
        mdlClass._startPosition <- cls._startPosition
        mdlClass._endPosition <- cls._endPosition
        mdlClass.Parent <- parentDomNode
        parentDomNode.InsertChild(GroupNames.ModelicaClasses,mdlClass)                
        let clsArray = Array.init cls._nestedClasses.Values.Count (fun x -> new Class() )
        cls._nestedClasses.Values.CopyTo(clsArray,0)
        let succsessors = Array.to_list(clsArray)
        createDomClassFromAst(succsessors,mdlClass,GroupNames.ModelicaClasses) 
        
        // this is for name lookup
        cls._domObject <- Some(mdlClass:> IDomNode)
               
        for annot in cls._annotations do
            insertMappedAnnotationToDomNode(annot,mdlClass,GroupNames.Annotations)            
            
        for comp in cls._components.Values do
            let domComp = createDomComponentFromAst(comp)
            domComp.Parent <- mdlClass   
            if comp._visibility = Visibility.Public then
                mdlClass.InsertChild(GroupNames.ModelicaPublicComponents,domComp)
            else
                mdlClass.InsertChild(GroupNames.ModelicaPublicComponents,domComp)                
            comp._domObject <- Some(domComp :> IDomNode) 
            
        let createDomInheritanceFromAst(astInherDecl:AstTypes.ExtendClause) =
            let domInherDecl = new InheritanceDeclaration()
            domInherDecl.refStatus <- ReferenceStatus.Unresolved
            //(domInherDecl :> IInheritanceDeclaration).Visibility <- Visibility.Protected            
            match astInherDecl._modification with 
            | Some modif ->
                createDomSubtreeFromClassModification(modif,domInherDecl) 
            | None -> ()
            match astInherDecl._annotation with
            | Some annot -> 
                insertMappedAnnotationToDomNode(annot,domInherDecl,GroupNames.Annotations)
            | None -> ()  
            domInherDecl.baseClassName <- astInherDecl._baseClassName
            astInherDecl._domObject <- Some(domInherDecl :> IDomNode)
            domInherDecl                      
        for astInherDecl in cls._protectedInheritsFrom.Values do
            let domInherDecl = createDomInheritanceFromAst(astInherDecl)
            (domInherDecl :> IInheritanceDeclaration).Visibility <- Visibility.Protected
            mdlClass.InsertChild(GroupNames.ModelicaProtectedInheritanceDeclaration,domInherDecl)                                
        for astInherDecl in cls._publicInheritsFrom.Values do
            let domInherDecl = createDomInheritanceFromAst(astInherDecl)
            (domInherDecl :> IInheritanceDeclaration).Visibility <- Visibility.Protected
            mdlClass.InsertChild(GroupNames.ModelicaPublicInheritanceDeclaration,domInherDecl)                    
        // equations and equations annotations
        resolveClassEquations(cls,mdlClass)
        for annot in cls._equationsAnnotations do
            insertMappedAnnotationToDomNode(annot,mdlClass,GroupNames.EquationAnnotations)  
        for annot in cls._initialEquationsAnnotations do
            insertMappedAnnotationToDomNode(annot,mdlClass,GroupNames.IninitalEquationAnnotations)      
            
and createDomSubtreeFromClassModification(modif:AstTypes.ClassModification, parentDomNode:IDomNode) =                     
    for compModif in modif._compModif.Values do
        let domCompModif = new ComponentModification()
        domCompModif.Parent <- parentDomNode
        (domCompModif :> IComponentModification).IsEach <- compModif._each
        (domCompModif :> IComponentModification).IsFinal <- compModif._final
        (domCompModif :> IComponentModification).ComponentRef <- compModif._compReference
        parentDomNode.InsertChild(GroupNames.ModelicaComponentModification,domCompModif)
    
    for astCompRedef in modif._compRedef.Values do
        let domCompRedef = new ComponentRedefinition() 
        (domCompRedef :> IComponentRedefinition).IsEach  <- (astCompRedef :> AstTypes.Redefinition)._each
        (domCompRedef :> IComponentRedefinition).IsFinal <- (astCompRedef :> AstTypes.Redefinition)._final
        (domCompRedef :> IComponentRedefinition).IsRedeclare <- (astCompRedef :> AstTypes.Redefinition)._redeclare
        (domCompRedef :> IComponentRedefinition).IsReplaceable <- (astCompRedef :> AstTypes.Redefinition)._replaceable
        let newComponent = createDomComponentFromAst(astCompRedef._component)
        if astCompRedef._component._visibility = Visibility.Public then
            domCompRedef.InsertChild(GroupNames.ModelicaPublicComponents,newComponent)
        else
            domCompRedef.InsertChild(GroupNames.ModelicaProtectedComponents,newComponent)                
        parentDomNode.InsertChild(GroupNames.ModelicaComponentRedefinition,domCompRedef)
    for astClassRedef in modif._classRedef.Values do 
        let domClassRedef = new ClassRedefinition() 
        (domClassRedef :> IClassRedefinition).IsEach  <- (astClassRedef :> AstTypes.Redefinition)._each
        (domClassRedef :> IClassRedefinition).IsFinal <- (astClassRedef :> AstTypes.Redefinition)._final
        (domClassRedef :> IClassRedefinition).IsRedeclare <- (astClassRedef :> AstTypes.Redefinition)._redeclare
        (domClassRedef :> IClassRedefinition).IsReplaceable <- (astClassRedef :> AstTypes.Redefinition)._replaceable
        let newClass = createDomClassFromAst([astClassRedef._class],domClassRedef,GroupNames.ModelicaClasses)                
        parentDomNode.InsertChild(GroupNames.ModelicaClassRedefinition,domClassRedef)
    ()
(***************************************
    Type Resolving in DOM
 ***************************************)


// searches in inheritance
let rec searchInheritanceForElementByName(name:string,searchStartClass:IDomNode) =
    let mutable foundElement = None
    let baseClsEnumerator = searchStartClass.GetChildren(GroupNames.ModelicaPublicInheritanceDeclaration).GetEnumerator()
    while (baseClsEnumerator.MoveNext() && foundElement.IsNone) do        
        foundElement <- findNameInModification(name,baseClsEnumerator.Current)                
        if foundElement.IsNone then           
            if(checkReferenceStatus((baseClsEnumerator.Current :?> InheritanceDeclaration).refStatus,(baseClsEnumerator.Current :?> InheritanceDeclaration),"searchInheritanceForElementByName")  = true ) then
                foundElement <- findElementByName(name, baseClsEnumerator.Current.GetReference(ReferenceNames.BaseClassReference).Reference )                              
    // inheritance - protected
    let baseClsEnumerator = searchStartClass.GetChildren(GroupNames.ModelicaProtectedInheritanceDeclaration).GetEnumerator()
    while (baseClsEnumerator.MoveNext() && foundElement.IsNone) do        
        foundElement <- findNameInModification(name,baseClsEnumerator.Current)        
        if foundElement.IsNone then  
            if(checkReferenceStatus((baseClsEnumerator.Current :?> InheritanceDeclaration).refStatus,(baseClsEnumerator.Current :?> InheritanceDeclaration),"searchInheritanceForElementByName") = true ) then
                foundElement <- findElementByName(name, baseClsEnumerator.Current.GetReference(ReferenceNames.BaseClassReference).Reference )
    foundElement

// searches imports for name
// TODO - imports with asterisk
and searchImportsForElementByName(name:string,searchStartClass:IDomNode) = 
    let mutable foundElement = None
    let publicImportsEnumerator = searchStartClass.GetChildren(GroupNames.ModelicaPublicImportDeclaration).GetEnumerator()
    while (publicImportsEnumerator.MoveNext() && foundElement.IsNone) do        
        let importDecl = publicImportsEnumerator.Current :?> IImportDeclaration         
        if importDecl.Alias = name then
            if(checkReferenceStatus((publicImportsEnumerator.Current :?> ImportDeclaration).refStatus,(publicImportsEnumerator.Current :?> ImportDeclaration),"searchImportsForElementByName") = true) then
                foundElement <- Some(publicImportsEnumerator.Current.GetReference(ReferenceNames.ImportedTypeReference).Reference)
            
    // imports - protected
    let protectedImportsEnumerator = searchStartClass.GetChildren(GroupNames.ModelicaProtectedImportDeclaration).GetEnumerator()
    while (protectedImportsEnumerator.MoveNext() && foundElement.IsNone) do        
        let importDecl = protectedImportsEnumerator.Current :?> IImportDeclaration         
        if importDecl.Alias = name then
            if(checkReferenceStatus((publicImportsEnumerator.Current :?> ImportDeclaration).refStatus,(publicImportsEnumerator.Current :?> ImportDeclaration),"searchImportsForElementByName") = true) then
                foundElement <- Some(protectedImportsEnumerator.Current.GetReference(ReferenceNames.ImportedTypeReference).Reference)
    foundElement
 
  
 
 // searches 
 and searchDomRootForBuiltIn(name:string) = 
    let domRoot = getDomRoot()
    let rootElementsEnumerator = (domRoot.GetChildren(GroupNames.ModelicaClasses)).GetEnumerator()
    let mutable foundElement = None
    while (rootElementsEnumerator.MoveNext() && foundElement.IsNone) do
        let rootMdlClass = rootElementsEnumerator.Current :?> IModelicaClass
        if rootMdlClass.ClassName = name then
            foundElement <- Some(rootElementsEnumerator.Current)
    
    match foundElement with
    | Some elem ->
        if ((elem :?> IModelicaClass).RestrictedType <> ModelicaClassType.Predefined) then
            None
        else
            foundElement
    | None ->
        None
        
// Search for class in modifications - look in class and components redefinitions, 
// component modifications not, as these can be arrays with indexes evaulated at runtime
and findNameInModification(name:string, modificatedDomNode:IDomNode) =    
    let compRedefEnumerator = (modificatedDomNode.GetChildren(GroupNames.ModelicaComponentRedefinition)).GetEnumerator()
    let mutable foundElement = None
    while (compRedefEnumerator.MoveNext() && foundElement.IsNone) do
        let compRedef = (compRedefEnumerator.Current :?> IComponentRedefinition)
        let compRedefDomNode = compRedefEnumerator.Current
        let mutable comp = compRedefDomNode.GetFirstChild(GroupNames.ModelicaPublicComponents)
        if comp <> null then
            foundElement <- Some(compRedefDomNode)
        else
            comp <- compRedefDomNode.GetFirstChild(GroupNames.ModelicaProtectedComponents)
            if comp <> null then
                foundElement <- Some(compRedefDomNode)                        
    
    let classRedefEnumerator = (modificatedDomNode.GetChildren(GroupNames.ModelicaClassRedefinition)).GetEnumerator()
    
    while (classRedefEnumerator.MoveNext() && foundElement.IsNone) do
        let classRedef = (compRedefEnumerator.Current :?> IComponentRedefinition)
        let classRedefDomNode = compRedefEnumerator.Current
        let mutable comp = classRedefDomNode.GetFirstChild(GroupNames.ModelicaClasses)
        if comp <> null then
            foundElement <- Some(classRedefDomNode)
        (*
        else
            comp <- classRedefDomNode.GetFirstChild(GroupNames.ModelicaPrivateClasses)
            if comp <> null then
                foundElement <- Some(classRedefDomNode)           
                *)
    foundElement

// search for class with the name in given dom node  
and findClassByName(className:string,searchStartDomNode:IDomNode) =     
    let nestedClsEnumerator = searchStartDomNode.GetChildren(GroupNames.ModelicaClasses).GetEnumerator()
    let mutable foundClass = None    
    while (nestedClsEnumerator.MoveNext() && foundClass.IsNone) do 
        if (nestedClsEnumerator.Current :?> IModelicaClass).ClassName = className then
            foundClass <- Some(nestedClsEnumerator.Current)            
     // TODO - when protected classes will be available, uncomment and modify this
     (*       
    while (nestedClsEnumerator.MoveNext() && foundClass.IsNone) do 
        if (nestedClsEnumerator.Current :?> IModelicaClass).ClassName = className then
            foundClass <- Some(nestedClsEnumerator.Current)             
       *)     
    foundClass    
                              
        
// search for component with the name in given dom node 
and findComponentByName(compName:string,searchStartDomNode:IDomNode) =     
    let mutable foundComponent = None
    // public components
    let compsEnumerator = searchStartDomNode.GetChildren(GroupNames.ModelicaPublicComponents).GetEnumerator()        
    while (compsEnumerator.MoveNext() && foundComponent.IsNone) do 
        if (compsEnumerator.Current :?> IComponent).ComponentName = compName then
            foundComponent <- Some(compsEnumerator.Current)
    // protected components
    let compsEnumerator = searchStartDomNode.GetChildren(GroupNames.ModelicaProtectedComponents).GetEnumerator()        
    while (compsEnumerator.MoveNext() && foundComponent.IsNone) do 
        if (compsEnumerator.Current :?> IComponent).ComponentName = compName then
            foundComponent <- Some(compsEnumerator.Current)
    foundComponent  

// finds element, starts from modelica class
and findElementByName(name:string, searchStartClass:IDomNode) = 
    if searchStartClass <> null then      
        let mutable foundElement = None
        foundElement <- findComponentByName(name, searchStartClass)
        if foundElement.IsNone then    
            foundElement <- findClassByName(name, searchStartClass)
        if foundElement.IsNone then
            foundElement <- searchInheritanceForElementByName(name,searchStartClass)
        if foundElement.IsNone then
            foundElement <- searchImportsForElementByName(name,searchStartClass)
        match foundElement with    
        | None ->                       
            let parent = searchStartClass.Parent
            match parent with
            | :? IDom ->              
                // in dom root there can be only classes
                findClassByName(name, parent)
            | null ->
                None
            | _ ->        
                let parentClass = (parent :?>IModelicaClass)
                match parentClass.Encapsulated with
                | false ->
                    findElementByName(name,parent)    
                | true ->
                    searchDomRootForBuiltIn(name)            
        | _ -> foundElement
    else
        None

and findElementByQualifiedName(qualifiedName:string list,searchStartClass:IDomNode) = 
    if qualifiedName.IsEmpty then
        raise(Exception("Trying to lookup empty name"))    
    let mutable foundElement = None
    let firstElement = findElementByName(qualifiedName.Head,searchStartClass)
    match firstElement with
    | Some firstElementVal ->
            match firstElement.Value with
            | :? IModelicaClass ->
                if qualifiedName.Tail.IsEmpty then
                    foundElement <- firstElement
                else
                    foundElement <- findElementByQualifiedName(qualifiedName.Tail,firstElementVal) 
            | :? IComponent -> 
                if qualifiedName.Tail.IsEmpty then            
                    foundElement <- firstElement
                else
                    if(checkReferenceStatus((firstElementVal :?> ModelicaComponent).refStatus,(firstElementVal :?> ModelicaComponent)," compnent") = true) then
                        let searchStart = firstElementVal.GetReference(ReferenceNames.ComponentTypeReference).Reference
                        foundElement <- findElementByQualifiedName(qualifiedName.Tail,searchStart)
            | :? IClassRedefinition ->
                if qualifiedName.Tail.IsEmpty then            
                    foundElement <- firstElement
                else
                    let searchStart = firstElementVal.GetFirstChild(GroupNames.ModelicaClasses)
                    foundElement <- findElementByQualifiedName(qualifiedName.Tail,searchStart)
            | :? IComponentRedefinition ->
                if qualifiedName.Tail.IsEmpty then            
                    foundElement <- firstElement
                else
                    let mutable compDef = firstElementVal.GetFirstChild(GroupNames.ModelicaPublicComponents)
                    if compDef = null then 
                        compDef <- firstElementVal.GetFirstChild(GroupNames.ModelicaProtectedComponents) 
                    let searchStart = compDef.GetReference(ReferenceNames.ComponentTypeReference).Reference
                    foundElement <- findElementByQualifiedName(qualifiedName.Tail,searchStart)
            | _ ->                
                let qNameStr = String.concat "." (List.to_seq(qualifiedName))
                //raise(Exception("Unknown referenced Dom Node found when resolving qualified name " + qNameStr ))                    
                log("*********** Unknown referenced Dom Node found when resolving qualified name *************")
            foundElement
    | None ->
        None

and resolveTypesInModifications(modificatedNode:IDomNode) = ()

and resolveInheritType(domInhDef:InheritanceDeclaration) = 
    if(domInhDef.refStatus <> ReferenceStatus.Set) then
        domInhDef.refStatus <- ReferenceStatus.Resolving
        let qualName = String.split ['.'] domInhDef.baseClassName
        let foundTypeOpt = findElementByQualifiedName(qualName,domInhDef.Parent.Parent)        
        match foundTypeOpt with
        | Some foundType ->            
            let reference = new DomReference(domInhDef)
            reference.Reference <- foundType
            domInhDef.refStatus <- ReferenceStatus.Set
            domInhDef.InsertReference(ReferenceNames.BaseClassReference,reference)
            //resolve types in modificatedTypes
            resolveTypesInModifications(domInhDef)
        | None ->
            domInhDef.refStatus <- ReferenceStatus.Invalid
            log("Inheritance type resolving failed on " + domInhDef.baseClassName + " in class " + getClassQualifiedName(domInhDef.Parent))

and resolveComponentType(domComp:ModelicaComponent) = 
    if(domComp.refStatus <> ReferenceStatus.Set) then
        domComp.refStatus <- ReferenceStatus.Resolving
        let qualName = String.split ['.'] domComp.typeName
        let foundTypeOpt = findElementByQualifiedName(qualName,domComp.Parent)        
        match foundTypeOpt with
        | Some foundType ->            
            let reference = new DomReference(domComp)
            reference.Reference <- foundType
            domComp.refStatus <- ReferenceStatus.Set
            domComp.InsertReference(ReferenceNames.ComponentTypeReference,reference)
            resolveTypesInModifications(domComp)
        | None ->   
            domComp.refStatus <- ReferenceStatus.Invalid         
            log("Component type resolving failed on " + domComp.typeName + " in class " + getClassQualifiedName(domComp.Parent) +  ".")  

and checkReferenceStatus(refStat:ReferenceStatus,domNode:IDomNode,source) =
    match refStat with
    | ReferenceStatus.Set ->
        true
    | ReferenceStatus.Resolving ->
        //false
        raise(Exception("Reference circle, cannot resolve " + source))
    | ReferenceStatus.Invalid ->
        //raise(Exception("Invalid reference " + source))
        false
    | ReferenceStatus.Unresolved ->
        //raise(Exception("Reference not set, we should continute, but we're not able right now" + source))
        match domNode with
        | :? ModelicaComponent ->
            resolveComponentType(domNode :?> ModelicaComponent)
            if ((domNode :?> ModelicaComponent).refStatus = ReferenceStatus.Set) then
                true
            else
                false
        | :? InheritanceDeclaration ->
            resolveInheritType(domNode :?> InheritanceDeclaration)
            if ((domNode :?> InheritanceDeclaration).refStatus = ReferenceStatus.Set) then
                true
            else
                false
        | :? ImportDeclaration ->
            raise(Exception("Reference not set, we should continute, but we're not able right now" + source))
        | _ ->
            raise(Exception("Unknown reference type " + source))
    | _ ->
        raise(Exception("Unknown reference status " + source))

let resolveImportedTypes(cls:Class) =    
    let resolveImportClause(cls:Class,impClause:ImportClause,visibility: Visibility) =             
        let domImportDecl = new ImportDeclaration()
        (domImportDecl :> IImportDeclaration).Alias <- impClause._alias
        (domImportDecl :> IImportDeclaration).ImportedName <- impClause._importedName
        domImportDecl.refStatus <- ReferenceStatus.Resolving
        let qualName = String.split ['.'] impClause._importedName        
        match impClause._importedName.EndsWith("*") with
        | true -> 
            let importNameWithoutStar = impClause._importedName.Substring(0,impClause._importedName.LastIndexOf("."))
            let foundTypeOpt = findElementByQualifiedName(qualName,cls._domObject.Value.Parent)
            match foundTypeOpt with
            | Some foundType ->    
                let reference = new DomReference(domImportDecl)
                reference.Reference <- foundType    
                domImportDecl.InsertReference(ReferenceNames.ImportedTypeReference,reference)
                domImportDecl.refStatus <- ReferenceStatus.Set
            | None -> 
                domImportDecl.refStatus <- ReferenceStatus.Invalid          
                log("Import type resolving failed on " + impClause._importedName + " in class " + cls._name +  ".")
        | false ->             
            // TODO potential error, when parent is Dom root            
            let foundTypeOpt = findElementByQualifiedName(qualName,cls._domObject.Value.Parent)
            match foundTypeOpt with
            | Some foundType ->                
                let reference = new DomReference(domImportDecl)
                reference.Reference <- foundType
                domImportDecl.refStatus <- ReferenceStatus.Set
                domImportDecl.InsertReference(ReferenceNames.ImportedTypeReference,reference)
            | None ->                
                domImportDecl.refStatus <- ReferenceStatus.Invalid
                log("Import type resolving failed on " + impClause._importedName + " in class " + cls._name +  ".")
                
        if visibility = Visibility.Public then
            cls._domObject.Value.InsertChild(GroupNames.ModelicaPublicImportDeclaration,domImportDecl)
        else
            cls._domObject.Value.InsertChild(GroupNames.ModelicaProtectedImportDeclaration,domImportDecl)
                
    for impClause in cls._publicImportedNames do
        resolveImportClause(cls,impClause,Visibility.Public)
        
    for impClause in cls._protectedImportedNames do
        resolveImportClause(cls,impClause,Visibility.Protected)
    
let resolveInheritTypes(cls:Class) =    
    for inhDef in cls._protectedInheritsFrom.Values do
        let domInhDef = inhDef._domObject.Value
        resolveInheritType(domInhDef:?> InheritanceDeclaration)
    for inhDef in cls._publicInheritsFrom.Values do
        let domInhDef = inhDef._domObject.Value
        resolveInheritType(domInhDef:?> InheritanceDeclaration)
        
let resolveComponentTypes(cls:Class) =        
    for comp in cls._components.Values do
        let domComp = comp._domObject.Value
        resolveComponentType((domComp :?> ModelicaComponent))

let getConnectClauses(cls:IDomNode) =        
    let rec searchInEqCollections(eqCollection) =
        let mutable connClList = []
        for eq:IDomNode in eqCollection do 
            match eq with
            | :? IConnectClause ->
                connClList <- (eq :?> IConnectClause) :: connClList
            | :? IFncCallEquation ->
                ()
            | :? IForEquation 
            | :? IWhenEquation 
            | :? IIfEquation ->            
                connClList <- connClList @ searchInEqCollections(eq.GetChildren(GroupNames.ModelicaEquations))
            | _ ->
                ()
        connClList
    searchInEqCollections(cls.GetChildren(GroupNames.ModelicaEquations)) @ searchInEqCollections(cls.GetChildren(GroupNames.ModelicaInitialEquations))   

// TODO implement this
let resolveConnectReferences(cls:Class) =
    let connClauseList = getConnectClauses(cls._domObject.Value)
    for connClause in connClauseList do
        let leftRefStr = AstOperations.createStringReference(connClause.LeftCompReference)        
        let leftComponent = findElementByQualifiedName(String.split ['.'] leftRefStr,cls._domObject.Value)              
        match leftComponent with
        | Some leftComponentVal ->
            let reference = new DomReference(leftComponentVal)
            (connClause :?> ConnectClause).InsertReference(ReferenceNames.ConnectClauseLeftSideReference,reference)
        | None ->
            log("Connect clause right reference resolving failed on " + leftRefStr + " in class " + getClassQualifiedName cls._domObject.Value)
        
        let rightRefStr = AstOperations.createStringReference(connClause.RightCompReference)
        let rightComponent = findElementByQualifiedName(String.split ['.'] rightRefStr,cls._domObject.Value)
        match rightComponent with
        | Some rightComponentVal ->
            let reference = new DomReference(rightComponentVal)
            (connClause :?> ConnectClause).InsertReference(ReferenceNames.ConnectClauseRightSideReference,reference)
        | None ->
            log("Connect clause left reference resolving failed on " + rightRefStr + " in class " + getClassQualifiedName cls._domObject.Value)
            
            
            
let rec resolveTypes(clsLst: Class list) = 
    match clsLst with
    | h::t ->                
        resolveImportedTypes(h)
        resolveInheritTypes(h)
        resolveComponentTypes(h)  
        resolveConnectReferences(h)        
        let nstClsArray = Array.init h._nestedClasses.Values.Count (fun x -> new Class() )
        h._nestedClasses.Values.CopyTo(nstClsArray,0)
        let nstClsLst = List.of_array nstClsArray
        resolveTypes(nstClsLst)
        resolveTypes(t)
    | [] ->
        ()
    
let rec resolveClassAndInsertIntoDom(clsLst: Class list,parentDomNode:IDomNode) =
    // for now just insert all classes as children of the root, later insertion point has to be found
    createDomClassFromAst(clsLst,parentDomNode,GroupNames.ModelicaClasses)
    resolveTypes(clsLst)